package client;


import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;


/**
 * Created by JossC on 2016/9/9.
 */
public class RPCClient {

    // 获取proxy代理类
    public static Object getProxy(String name, String host, int port)
        throws ClassNotFoundException, UnknownHostException {
        // 创建接口实例
        Class<?> interfaceClass = Class.forName(name);
        InvocationHandler handler = new ClientInvocationHandler(name, InetAddress.getByName(host),
            port);
        // 调用handler的invoke方法
        return Proxy.newProxyInstance(RPCClient.class.getClassLoader(),
            new Class<?>[] {interfaceClass}, handler);
    }

    /**
     * 静态私有内部类，该类是RPCclient私有的组件
     *
     * @author 蔡强
     * @version 2016年9月18日
     * @see ClientInvocationHandler
     * @since
     */
    private static class ClientInvocationHandler implements InvocationHandler {
        private InetAddress address;

        private int port;

        private String name;

        // 发送信息，等待返回结果
        public ClientInvocationHandler(String name, InetAddress address, int port) {
            super();
            this.address = address;
            this.name = name;
            this.port = port;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {

            // 把调用服务所需的信息封装bean中
            InvokerBean in = new InvokerBean(name, new RPCMethod(method.getName(),
                method.getParameterTypes()), args);
            // 启动 sokcet
            Socket client = new Socket(address, port);
            // 把序列化对象转成流
            ObjectOutputStream oos = new ObjectOutputStream(client.getOutputStream());
            oos.writeObject(in);
            oos.flush();
            // 读取服务端返回结果
            ObjectInputStream ois = new ObjectInputStream(client.getInputStream());
            in = (InvokerBean)ois.readObject();
            oos.close();
            ois.close();
            client.close();
            return in.getResult();
        }
    }
}